local LUI = LibStub("AceAddon-3.0"):GetAddon("LUI");
local LSM = LibStub("LibSharedMedia-3.0")
local widgetLists = AceGUIWidgetLSMlists
local LUIHook = LUI:GetModule("LUIHook")
local module = LUI:NewModule("Reputation", "AceHook-3.0")

local mediaPath = [=[Interface\Addons\oUF_LUI\media\]=]
local blankTex = mediaPath..[=[textures\blank]=]
local glowTex = mediaPath..[=[texture\glowTex]=]

local backdrop = {
	bgFile = blankTex,
	edgeFile = glowTex,
	edgeSize = 5,
	insets = {top = -1, left = -1, bottom = -1, right = -1},
}

local defaults = {
	Reputation = {
		Enable = true,
		Watched = {},
		xPos = 50,
		yPos = 50
	},
}
local function LUI_Reputation_Chat_Filter(frame, event, message, ...)
	if (not module) then
		print("Unable to locate 'self' in Reputation chat filter!");
		return;
	end
	local _, _, factionName, amount = string.find(message, module:FormatString(FACTION_STANDING_DECREASED));
	--local val = self.statusBar:GetValue();
	local found = false;

	if not factionName then
		_, _, factionName, amount = string.find(message, module:FormatString(FACTION_STANDING_INCREASED));
	end
	if not factionName then
		print("ERROR : Passed both options and no name found!");
		print("      "..message);
		return;
	end
	amount = tonumber(amount);
	for i,v in ipairs(module.factions) do
		if (v.name == factionName) then
			v.current = v.current + amount;
			module:SetBarValues(v, false);
		end
	end
end
local function LUI_Reputation_Chat_Filter_Reload(frame, event, message, ...)
	local _, _, repLevel, factionName = string.find(message, module:FormatString(FACTION_STANDING_CHANGED));
	if (not factionName) then
		return;
	end
	if (factionName == module.lastRenew) then
		return;
	end
	module.lastRenew = factionName;
	for i,v in ipairs(module.factions) do
		if (v.name == factionName) then
			local factName, desc, standingId, bottomValue, topValue, earnedValue, atWarWith, canToggleAtWar, isHeader, isCollapsed, hasRep, isWatched, isChild = GetFactionInfo(v.id);
			v.standing = standingId;
			v.low = bottomValue;
			v.high = topValue;
			v.current = earnedValue;
			module:SetBarValues(v, true);
		end
	end
end
function module:SetBarValues(v, setall)
	if (setall) then
		v.statusBar:SetMinMaxValues(v.low, v.high);
		v.statusBar:SetStatusBarColor(FACTION_BAR_COLORS[v.standing].r, FACTION_BAR_COLORS[v.standing].g, FACTION_BAR_COLORS[v.standing].b);
	end
	v.statusBar.txt:SetText(v.name.." - "..v.current .."/"..v.high);
	v.statusBar:SetValue(v.current);
end
function module:LoadOptions()
	local options = {
		Reputation = {
			name = "Reputation",
			type = "group",
			order = 45,
			disabled = function() return not db.Reputation.Enable end,
			childGroups = "select",
			args = {
				empty = {
					name = " \n ",
					width = "full",
					type = "description",
					order = 1,
				},
				desc = {
					name = "|cff3399ffNotice:|r\nReputation Options will be included within the next module Update.",
					width = "full",
					type = "description",
					order = 2,
				},
			},
		},
	}
	return options
end

function module:LoadModule()
	local module = {
		Reputation = {
			order = LUI:GetModuleCount(),
			type = "execute",
			name = function()
				if db.Reputation.Enable then
					return "|cff00ff00Reputation Enabled|r"
				else
					return "|cffFF0000Reputation Disabled|r"
				end
			end,
			func = function(self, Reputation)
				db.Reputation.Enable = not db.Reputation.Enable
				StaticPopup_Show("RELOAD_UI")
			end,
		},
	}
	return module
end

function module:OnInitialize()
	LUI:MergeDefaults(LUI.db.defaults.profile, defaults)
	LUI:RefreshDefaults()
	LUI:Refresh()
	
	self.db = LUI.db.profile
	db = self.db
end
function module:OnEnable()
	LUI:RegisterOptions(self:LoadOptions());
	LUI:RegisterModule(self:LoadModule());
	if (db.Reputation.Enable) then
		self:SetCommands();
		if (#db.Reputation.Watched > 0) then
			module:CreateWatchedFactions();
			self:ResizeFrame();
		else
			self:CreateFactions();
		end
		ChatFrame_AddMessageEventFilter("CHAT_MSG_COMBAT_FACTION_CHANGE", LUI_Reputation_Chat_Filter);
		ChatFrame_AddMessageEventFilter("CHAT_MSG_SYSTEM", LUI_Reputation_Chat_Filter_Reload);
	end
	--self:CreateFrameButton();
end
function module:CreateMainFrame()
	local f = CreateFrame("Frame", "LUIReputationFrame", UIParent);
	--f:SetFrameStrata("BACKGROUND");
	f:RegisterEvent("PLAYER_ENTERING_WORLD");
	f:SetScript("OnEvent", function(frame, event, ...)
		if (event == "PLAYER_ENTERING_WORLD") then
			if (db.Reputation.xPos > 0 and db.Reputation.yPos > 0) then
				frame:ClearAllPoints();
				frame:SetPoint("TOPLEFT", UIParent, "TOPLEFT", db.Reputation.xPos, db.Reputation.yPos);
				frame:UnregisterEvent("PLAYER_ENTERING_WORLD");
			else
				frame:SetPoint("CENTER", 50, 50);
			end
		end
	end);
	local hdr = f:CreateFontString(nil, "OVERLAY");
	hdr:SetPoint("TOPLEFT", f, "TOPLEFT", 0, 0);
	hdr:SetJustifyH("CENTER");
	hdr:SetFont(LSM:Fetch("font", db.Info.Bags.Font), 14, "NONE");
	hdr:SetText("LUI Reputation");
	hdr:SetTextColor(0, 0, 0);
	hdr:SetWidth(210);
	hdr:SetHeight(30);
	hdr:Show();
	f.header = hdr;
	
	f:SetWidth(210);
	f:SetHeight(165);
	f:SetBackdrop(backdrop);
	f:SetMovable(true);
	f:EnableMouse(true);
	f:SetUserPlaced(true);
	f:RegisterForDrag("LeftButton");
	f:SetScript("OnDragStart", f.StartMoving);
	f:SetScript("OnDragStop", f.StopMovingOrSizing);
	--f:SetBackdropColor(0, 0, 0, 1);
	f:Show();
	self.frame = f;
end
function module:CreateBar(prev, faction)
	local f = CreateFrame("StatusBar", "LUI_Faction_"..faction.name, self.frame);
	f:SetWidth(200);
	f:SetHeight(20);
	f:SetScale(1);
	local pt = "BOTTOMLEFT";
	local offset = -5;
	local xoff = 0;
	if (not prev) then
		pt = "TOPLEFT";
		prev = self.frame;
		offset = -(module.frame.header:GetHeight()+5);
		--offset = 0;
		xoff = 5;
	end
	f:SetPoint("TOPLEFT", prev, pt, xoff, offset);
	f:SetAlpha(1);

	f:SetStatusBarTexture([=[Interface\AddOns\LUI\media\textures\statusbars\Ruben.tga]=]);
	local b = backdrop;
	b.edgeFile = nil;
	b.edgeSize = 0;
	f:SetBackdrop(b);
	f:SetBackdropColor(0, 0, 0, 1);
	local FONT_SIZE = 10;
	local FONT = LSM:Fetch("font", db.Info.Bags.Font);
	
	local txt = f:CreateFontString(nil, "OVERLAY");
	txt:SetPoint("CENTER", LUI:Scale(2), LUI:Scale(0));
	txt:SetJustifyH("CENTER");
	txt:SetFont(FONT, FONT_SIZE, "OUTLINE");
	txt:SetShadowColor(0, 0, 0, 0.5);
	txt:SetShadowOffset(2, -2);
	txt:SetText(faction.name .. " - " .. faction.current .. "/" .. faction.high);
	f.txt = txt;
	f:SetMinMaxValues(faction.low, faction.high);
	f:SetValue(faction.current);
	f:SetStatusBarColor(FACTION_BAR_COLORS[faction.standing].r, FACTION_BAR_COLORS[faction.standing].g, FACTION_BAR_COLORS[faction.standing].b);
	faction.statusBar = f;

	local btn = CreateFrame("Button", "LUI_Faction_"..faction.name.."_btn", f);
	btn:SetWidth(200);
	btn:SetHeight(20);
	btn:SetPoint("TOPLEFT", f, "TOPLEFT", 0, 0);
	btn:RegisterForClicks("RightButtonUp");
	btn:SetScript("OnClick", function(frame, button) 
		module:RemoveStatusBar(frame:GetParent():GetName());
	end);
	btn:Show();
	f.button = btn;
	f:Show();
	txt:Show();
	return f;
end
function module:RemoveStatusBar(parentName)
	local faction = nil;
	local pos = nil;
	for i,v in pairs(module.factions) do
		if (v.statusBar:GetName() == parentName) then
			faction = v;
			pos = i;
		end
	end
	if not faction then
		print("Reputation:RemoveStatusBar - Faction empty.");
		return;
	end
	if (not faction.statusBar) then
		print("Reputation:RemoveStatusBar - Faction found, but no statusBar.");
		return;
	end
	self.factionCount = self.factionCount - 1;
	faction.statusBar.txt:Hide();
	faction.statusBar.txt = nil;
	faction.statusBar:Hide();
	faction.statusBar.button:Hide();
	faction.statusBar.button = nil;
	faction.statusBar = nil;
	table.remove(module.factions, pos);
	faction = nil;
	module:RepositionBars();
	module:ResizeFrame();
end
function module:RepositionBars()
	local prev = nil;
	for i,v in pairs(module.factions) do
		local pt = "BOTTOMLEFT";
		local offset = -5;
		local xoff = 0;

		if (not prev) then
			pt = "TOPLEFT";
			prev = self.frame;
			offset = -(module.frame.header:GetHeight()+5);
			xoff = 5;
		end
		v.statusBar:SetPoint("TOPLEFT", prev, pt, xoff, offset);
		prev = v.statusBar;
	end
end
function module:ResizeFrame()
	self.frame:SetHeight(((self.factionCount * 20)+(5*self.factionCount)+5)+self.frame.header:GetHeight());
end

function module:CreateWatchedFactions()
	module.self = self;
	self.factionCount = 0;
	self.factions = {}
	self:SetStrings();
	self:CreateMainFrame();
	local lastBar = nil;
	for factionIndex = 1, GetNumFactions() do
		local factName, desc, standingId, bottomValue, topValue, earnedValue, atWarWith, canToggleAtWar, isHeader, isCollapsed, hasRep, isWatched, isChild = GetFactionInfo(factionIndex);
		for i, v in ipairs(db.Reputation.Watched) do
			if (factName == v.name) then
				local f = {
					id = factionIndex,
					name = factName,
					description = desc,
					standing = standingId,
					low = bottomValue,
					high = topValue,
					current = earnedValue,
					atWar = atWarWith,
					watched = isWatched,
					enabled = (isHeader and hasRep or not isHeader),
				}
				if (f.enabled) then
					self.factionCount = self.factionCount + 1;
					lastBar = self:CreateBar(lastBar, f);
					table.insert(self.factions, f);
				end
			end
		end
	end
end
function module:SetStrings()
	self.FACTION_STANDING_CHANGED = self:FormatString(FACTION_STANDING_CHANGED);
	self.FACTION_STANDING_DECREASED = self:FormatString(FACTION_STANDING_DECREASED);
	self.FACTION_STANDING_INCREASED = self:FormatString(FACTION_STANDING_DECREASED);
end
function module:CreateFactions()
	module.self = self;
	module:SetStrings();
	self.factions = {};
	self.factionCount = 0;
	if (not db.Reputation.Enable) then
		return;
	end
	self:CreateMainFrame();
	local lastBar = nil;
	for factionIndex = 1, GetNumFactions() do
		local factName, desc, standingId, bottomValue, topValue, earnedValue, atWarWith, canToggleAtWar, isHeader, isCollapsed, hasRep, isWatched, isChild = GetFactionInfo(factionIndex);
		local f = {
			id = factionIndex,
			name = factName,
			description = desc,
			standing = standingId,
			low = bottomValue,
			high = topValue,
			current = earnedValue,
			atWar = atWarWith,
			watched = isWatched,
			enabled = (isHeader and hasRep or not isHeader),
		}
		if (f.enabled) then
			self.factionCount = self.factionCount + 1;
			lastBar = self:CreateBar(lastBar, f);
			table.insert(self.factions, f);
		end
	end
	print("Reputation: Loaded "..#self.factions.." ("..self.factionCount..") factions!");
	self:ResizeFrame();
end
function module:SetCommands()
	if (not db.Reputation.Enable) then
		return;
	end
	SLASH_LUIREP1 = "/rep";
	SlashCmdList["LUIREP"] = function(msg)
		if (msg and msg == "save") then
			db.Reputation.Watched = {};
			for i,v in ipairs(self.factions) do
				local f = { name = v.name }
				table.insert(db.Reputation.Watched, f);
			end
			print("Saved "..#db.Reputation.Watched.." factions.");
			db.Reputation.xPos = self.frame:GetLeft();
			db.Reputation.yPos = self.frame:GetTop();
		elseif (msg and msg == "clear") then
			db.Reputation.Watched = {};
			self:ClearAll();
			self:CreateFactions();
			self.frame:SetPoint("CENTER", 0, 0);
			self.frame:Show();
		elseif (msg and msg == "hide") then
			self.frame:Hide();
		elseif (msg and msg == "show") then
			self.frame:Show();
		else
			self:DisplayFactions();
		end
	end;
end
function module:ClearAll()
	for i,faction in ipairs(self.factions) do
		self.factionCount = self.factionCount - 1;
		faction.statusBar.txt:Hide();
		faction.statusBar.txt = nil;
		faction.statusBar:Hide();
		faction.statusBar.button:Hide();
		faction.statusBar.button = nil;
		faction.statusBar = nil;
	end
	self.factions = {};
	self.frame.header:Hide();
	self.frame.header = nil;
	self.frame:Hide();
	self.frame = nil;
end
function module:HideFactions()
	ReputationFrame:Hide();
end
function module:DisplayFactions()
	ReputationFrame:Show();
end
function module:FormatString(formatString)
	local patternString = formatString;
	patternString = string.gsub(patternString, "%%%d+%$([diouXxfgbcsq])", "%%%1"); -- reordering specifiers (e.g. %2$s) stripped	
	patternString = string.gsub(patternString, "([%$%(%)%.%[%]%*%+%-%?%^])", "%%%1"); -- convert regex special characters
	patternString = string.gsub(patternString, "%%c", "(.)"); -- %c to (.)
	patternString = string.gsub(patternString, "%%s", "(.+)"); -- %s to (.+)
	patternString = string.gsub(patternString, "%%[du]", "(%%d+)"); -- %d to (%d+)
	patternString = string.gsub(patternString, "%%([gf])", "(%%d+%%.*%%d*)"); -- %g or %f to (%d+%.*%d*)
	return patternString;
end
